package com.study.example.lock;

import com.study.annoations.ThreadUnsafe;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author 贺瑞杰
 * @version V1.0
 * @date 2018-05-27 22:58
 * @description 模拟高并发的测试类 使用CountDownLatch 和 Semaphore 类
 * 这是线程不安全的写法
 */
@ThreadUnsafe
@Slf4j
public class LockExample1 {

    /**
     * 请求总数
     */
    private static int clientTotal = 50000;

    /**
     * 同时并发执行的线程数
     */
    private static int threadTotal = 200;

    private static int count = 0;

    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal; i++) {
            executorService.execute(() -> {
                try {
                    // 当前这个线程是否允许被执行 如果acquire不能返回值则add()的方法不被执行 返回则可以
                    semaphore.acquire();
                    add();
                    // 释放当前的进程
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 每执行返一次clientTotal的值就会减一个
                countDownLatch.countDown();
            });
        }
        try {
            // 当所有请求执行完毕才可以走下面的方法 及clientTotal减为0
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 关闭线程池
        executorService.shutdown();
        long end = System.currentTimeMillis();
        log.info("count:{}", count);
        log.info("使用时间：" + (end - start));
    }

    private static void add() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }


}